package com.lenovo.vod.player;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Timer;

import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.widget.Toast;

//import com.lenovo.dll.nebula.vod.detail.RelateFragment;
import com.lenovo.dll.nebula.vod.parse.handler.PlayUrlHandler;
import com.lenovo.dll.nebula.vod.parse.service.IPlayUrlService;
import com.lenovo.vod.player.callback.BufferingUpdateListener;
import com.lenovo.vod.player.callback.CompletionListener;
import com.lenovo.vod.player.callback.ErrorListener;
import com.lenovo.vod.player.callback.KeyListener;
import com.lenovo.vod.player.callback.PreparedListener;
import com.lenovo.vod.player.callback.SeekBarChangeListener;
import com.lenovo.vod.player.callback.SurfaceHolderCallback;
import com.lenovo.vod.player.callback.TouchListener;
import com.lenovo.vod.player.callback.VideoSizeChangedListener;
import com.lenovo.vod.player.setting.SettingFragment;
import com.lenovo.vod.player.util.HideControllerTask;
import com.lenovo.vod.player.util.M3u8Parser;
import com.lenovo.vod.player.util.SettingHandler;
import com.lenovo.vod.player.util.TimerTaskHandler;
import com.lenovo.vod.player.util.UpdateProgressTask;
import com.lenovo.dll.nebula.vod.parse.service.PlayUrlService;
//import com.lenovo.vod.player.playend.PlayEndActivity;

public class Engine {
	// fragment and activity
	private ContentFragment mContentFragment;
	private ControllerFragment mControllerFragment;
	private SettingFragment mSettingFragment;
//	private RelateFragment mRelateFragment;
	private MainActivity mActivity;

	// MediaPlayer listener
	private BufferingUpdateListener mBufferingUpdateListener;
	private CompletionListener mCompletionListener;
	private PreparedListener mPreparedListener;
	private VideoSizeChangedListener mVideoSizeChangedListener;
	private ErrorListener mErrorListener;

	// dialog listener
	private DialogInterface.OnClickListener mBlackScreenInterface;

	// m3u8 parser
	private M3u8Parser mM3u8Parser;

	// timer
	private Timer mUpdateProgressTimer;
	private Timer mHideControllerTimer;

	// handler
	private TimerTaskHandler mTimerTaskHandler;
	private SettingHandler mSettingHandler;

	// get paly url interface
	private IPlayUrlService<String> mGetPlayAddrInterface;

	// play paras
	private MediaPlayer mMediaPlayer;
	private SurfaceHolder mHolder;
	private String mPlayAddr;
	private int mVideoWidth;
	private int mVideoHeight;
	private boolean mIsVideoSizeKnown = false;
	private boolean mIsVideoReadyToBePlayed = false;
	private boolean mInited = false;
	private boolean mIsPlaying;

	// controller paras
	private boolean mIsControllerShowed;

	// setting paras
	private String mDefinition;
	private boolean mIsBreakpointPlay;

	// buffer paras
	private boolean mBufferCompleted = false;
	private boolean mBufferStarted = false;

	// fast backword or forward paras
	private final static int mFastSeekUnit = 30;
	private int mKeyLeftCount = 0;
	private int mKeyRightCount = 0;
	private int mFastSeekStep = 1;
	private final static int mAcceleration = 1;
	private final static int mFastSeekStartAt = 5;
	private int mSeekPosition;

	// paras from other activity
	private Bundle mExtras;
	private Bundle mRelateBundle;
	private int mCurrentVideoNum;
	private int mTotalVideoNum;
	private boolean mIsMovie;
	private Bundle mDetailData;
	private boolean mHasRecommend = false;
	private boolean mStartFromBeginning = false;
	private String mItemCode;
	private String mVideoCode;
	private int mItemType;

	// volume paras
	private int mVolume = 50;
	private int mVolumeBack = 50;
	private boolean mIsMute = false;
	private AudioManager mAudioManager;

	// timer for long press
	private long    mLastPressTime = 0;
	private long    mLongPressSpan = 100;
	private boolean mIsLongPress   = false;
	
	// date format
	private SimpleDateFormat mDateFormat;

	public Engine(MainActivity activity) {
		mContentFragment = activity.getContentFragment();
		mControllerFragment = activity.getControllerFragment();
		mSettingFragment = activity.getSettingFragment();
//		mRelateFragment = activity.getRelateFragment();
		mActivity = activity;

		mContentFragment.showBackgound();
		showBuffer(0);

		mHolder = mContentFragment.getSurfaceView().getHolder();
		mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

		mTimerTaskHandler = new TimerTaskHandler(this);
		mSettingHandler = new SettingHandler(this);

		mAudioManager = (AudioManager) mActivity
				.getSystemService(Context.AUDIO_SERVICE);
		mVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);

		mDateFormat = new SimpleDateFormat("HH:mm:ss");

		mM3u8Parser = new M3u8Parser();

		mGetPlayAddrInterface = new PlayUrlService<String>(new PlayUrlHandler());

		setListener();

		getParas();
	}

	public void setListener() {
		// set listener for ContentFragment
		mContentFragment.getView().setOnTouchListener(new TouchListener(this));
		mContentFragment.getView().setOnKeyListener(new KeyListener(this));
		mHolder.addCallback(new SurfaceHolderCallback(this));

		// set listener for ControllerFragment
		mControllerFragment.getSeekBar().setOnSeekBarChangeListener(
				new SeekBarChangeListener(this));

		// new listener for MediaPlayer
		mBufferingUpdateListener = new BufferingUpdateListener(this);
		mCompletionListener = new CompletionListener(this);
		mPreparedListener = new PreparedListener(this);
		mVideoSizeChangedListener = new VideoSizeChangedListener(this);
		mErrorListener = new ErrorListener(this);

		// new listener for dialog
		mBlackScreenInterface = new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				end();
				hideController();
			}
		};
	}

	public void setMediaPlayerListener() {
		if (mPlayAddr.startsWith("http")) {
			mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
			// mMediaPlayer.setOnErrorListener(mErrorListener);
		}
		mMediaPlayer.setOnCompletionListener(mCompletionListener);
		mMediaPlayer.setOnPreparedListener(mPreparedListener);
		mMediaPlayer.setOnVideoSizeChangedListener(mVideoSizeChangedListener);
	}

	public void getParas() {
		mExtras = mActivity.getIntent().getExtras();
		mRelateBundle = mExtras.getBundle("Relate");
		mCurrentVideoNum = mExtras.getInt("PlayEpisode");

		if (mExtras.getInt("Type") == 0)
			mIsMovie = true;
		else
			mIsMovie = false;
		mDetailData = mExtras.getBundle("EpisodeDetail");
		mTotalVideoNum = mDetailData.size();
		mControllerFragment.setTitle(mExtras.getString("Name"));
		if (mCurrentVideoNum == 0) {
			mCurrentVideoNum = 1;
			mStartFromBeginning = true;
		}

		mItemCode = mExtras.getString("Code");
		mItemType = mExtras.getInt("ItemType");
	}

	public void setPlayAddr(String playAddr) 
	{
		Log.d(Constant.TAG, "setPlayAddr called[playAddr:" + mPlayAddr + "]");

		// playAddr will be null when the video is firstly called
		// use the parameters from XML file to fetch the playAddr by server
		if (playAddr == null) 
		{
			mVideoCode = mDetailData
					    .getBundle(String.valueOf(mCurrentVideoNum))
					    .getString("VideoCode");

			try 
			{
				Log.d(Constant.TAG, "to get PlayUrl:" + mPlayAddr);
				
				// mGetPlayAddrInterface is a interface and BCTI implement is PlayUrlSerivce class
	        	mPlayAddr = mGetPlayAddrInterface.getPlayUrl(mItemType  ,
						                                     mItemCode  , 
						                                     mVideoCode );
				
				Log.d(Constant.TAG, "PlayUrl:" + mPlayAddr);
			}
			catch (ParserConfigurationException e)
			{
				Log.e(Constant.TAG, "error: " + e.getMessage(), e);
				destroy();
			}
			catch (SAXException e)
			{
				Log.e(Constant.TAG, "error: " + e.getMessage(), e);
				destroy();
			}
			catch (IOException e)
			{
				Log.e(Constant.TAG, "error: " + e.getMessage(), e);
				destroy();
			}

			mM3u8Parser.parse(mPlayAddr);
			mSettingFragment.setMovieDefinition(mM3u8Parser.getDefinations());
		} 
		else
		{
			mPlayAddr = playAddr;
		}

		if (mDefinition != null && 
			!mDefinition.equals(Constant.PARA_DEFINITION_ADAPTION))
		{
			mPlayAddr = mM3u8Parser.getSecondLevelUrl(mDefinition);
		}
	}

	public void init() 
	{
		if (mInited)// my be inited more than once for event called
			return;

		mInited = true;

		int duration = getDuration();
		mControllerFragment.setDuration(duration);
		mControllerFragment.setTotalTime(mDateFormat.format(duration));

		seekToLastExit();

		// set progress timer
		if (getDuration() > 0) 
		{
			mUpdateProgressTimer = new Timer();
			mUpdateProgressTimer
					.schedule(new UpdateProgressTask(this), 0, 1000);
		}

		hideBuffer();
		mContentFragment.hideBackgound();
		showControllerTimed();
	}

	public void play(String playAddr) {
		end();
		mContentFragment.showBackgound();
		setPlayAddr(playAddr);
		// mPlayAddr = "http://img.3g.youku.com/test/m3u8/v.m3u8";

		Log.d(Constant.TAG, "play called[uri:" + mPlayAddr + "]");

		mMediaPlayer = new MediaPlayer();
		setMediaPlayerListener();

		try {
			mMediaPlayer.setDataSource(mPlayAddr);
			mMediaPlayer.setDisplay(mHolder);
			mMediaPlayer.prepareAsync();
			mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
		} catch (Exception e) {
			Log.e(Constant.TAG, "show AlertDialog error: " + e.getMessage(), e);
			showAlertDialog(R.string.vodplayer_error_video_cannot_play, 0,
					mBlackScreenInterface, null,
					R.string.vodplayer_error_video_cannot_play);
		}
	}

	public void playNext() {
		Log.d(Constant.TAG, "playNext called");

		if (mCurrentVideoNum < mTotalVideoNum) {
			mCurrentVideoNum++;
			play(null);
		} else {
			destroy();
		}
	}

	public void playPrevious() {
		Log.d(Constant.TAG, "playPrevious called");

		if (mCurrentVideoNum > 1) {
			mCurrentVideoNum--;

			play(null);
		} else {
			destroy();
		}
	}

	public boolean isPlaying() {
		if (mMediaPlayer != null)
			return mMediaPlayer.isPlaying();
		else
			return false;
	}

	public int getCurrentPosition() {
		if (mMediaPlayer != null) {
			return mMediaPlayer.getCurrentPosition();
		} else {
			return 0;
		}
	}

	public int getDuration() {
		if (mMediaPlayer != null) {
			return mMediaPlayer.getDuration();
		} else {
			return 0;
		}
	}

	public void setVolume(boolean add) {

		if (add) {
			mVolume++;
		} else {
			mVolume--;
		}
		mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, mVolume, 0);
	}

	public void setMute() {
		if (mIsMute) {
			Log.d(Constant.TAG, "setMute called[mVolumeBack:" + mVolumeBack
					+ "]");
			mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
					mVolumeBack, 0);
			mIsMute = false;
		} else {
			Log.d(Constant.TAG, "VideoContentFragment setMute called[mVolume:"
					+ mVolume + "]");
			mVolumeBack = mVolume;
			mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0);
			mIsMute = true;
		}
	}

	public void start() {
		Log.d(Constant.TAG, "start called");

		mMediaPlayer.start();
		mIsPlaying = true;
		mControllerFragment.setPause(false);
	}

	public void pause() {
		Log.d(Constant.TAG, "pause called");

		mMediaPlayer.pause();
		mControllerFragment.setPause(true);
	}

	public void pauseOrStart() {
		Log.d(Constant.TAG, "pauseOrStart called");

		if (mIsPlaying) {
			mIsPlaying = false;
			pause();
		} else {
			mIsPlaying = true;
			start();
		}
	};

	public void seekTo(int pos) {
		Log.d(Constant.TAG, "seekTo called: " + pos);
		mMediaPlayer.seekTo(pos);
		mSeekPosition = pos;
	}

	public void seekToLastExit() {
		// set play point
		int lastExitTime = mDetailData.getBundle(
				String.valueOf(mCurrentVideoNum)).getInt("LastExitTime");
		if (!mStartFromBeginning) {// from detail activity
			setProgress(lastExitTime);
		} else {
			if (mIsBreakpointPlay) {// from setting
				setProgress(lastExitTime);
			}
		}
	}

	public void resetSeek() {
		mKeyLeftCount = 0;
		mKeyRightCount = 0;
		mFastSeekStep = mFastSeekUnit;

		mControllerFragment.setFastForward(false);
		mControllerFragment.setFastBackward(false);
	}

	public void fastForWard() 
	{
		mControllerFragment.setFastForward(true);

		mSeekPosition = getCurrentPosition();
		int duration = getDuration();

		mControllerFragment.show();

		if (mKeyRightCount >= mFastSeekStartAt)
			mFastSeekStep += mAcceleration;

		mSeekPosition = mSeekPosition + mFastSeekStep * 1000;
		
		if (mSeekPosition > duration)
		{
			seekTo(duration);
		}
		else
		{
			if( (this.mKeyRightCount % 10) == 1 )
			{
				seekTo(mSeekPosition);
			}
			else
			{
				Log.i("VODPlayer", 
					  "Right Long Press Not Response rigthCount[" + 
					  this.mKeyRightCount +"]");
				
				return;
			}
		}	
	}

	public void fastBackWard() 
	{
		mControllerFragment.setFastBackward(true);

		mSeekPosition = getCurrentPosition();
		mControllerFragment.show();

		if (mKeyLeftCount >= mFastSeekStartAt)
			mFastSeekStep += mAcceleration;

		mSeekPosition = mSeekPosition - mFastSeekStep * 1000;
		
		if (mSeekPosition < 0)
		{
			seekTo(0);
		}
		else
		{
			if( (this.mKeyLeftCount % 10) == 1)
			{
				seekTo(mSeekPosition);
			}
			else
			{
				Log.i("VODPlayer", 
					  "Left Long Press Not Response leftCount[" + 
					  this.mKeyLeftCount +"]");
				
				return;
			}
		}	
	}
	
	public void end() {
		Log.d(Constant.TAG, "end called");

		mTimerTaskHandler.removeMessages(Constant.MSG_HIDE_CONTROLLER);
		mTimerTaskHandler.removeMessages(Constant.MSG_UPDATE_PROGRESS);

		if (mUpdateProgressTimer != null) {
			mUpdateProgressTimer.cancel();
			mUpdateProgressTimer = null;
		}

		if (mHideControllerTimer != null) {
			mHideControllerTimer.cancel();
			mHideControllerTimer = null;
		}

		if (mMediaPlayer != null) {
			mMediaPlayer.release();
			mMediaPlayer = null;
		}
		mVideoWidth = 0;
		mVideoHeight = 0;
		mIsVideoReadyToBePlayed = false;
		mIsVideoSizeKnown = false;

		mBufferStarted = false;
		mBufferCompleted = false;

		mInited = false;
		mIsPlaying = false;
	}

	public void destroy() {
		Log.d(Constant.TAG, "destroy called");

		end();

		nextActivity();

		mActivity.finish();
	}

	public void showOrHideController() {
		if (mIsControllerShowed) {
			hideController();
		} else {
			showControllerTimed();
		}
	}

	public void showControllerTimed() {
		Log.d(Constant.TAG, "showControllerTimed called");

		showController();

		mHideControllerTimer = new Timer();
		mHideControllerTimer.schedule(new HideControllerTask(this), 6000);
	}

	public void showController() {
		Log.d(Constant.TAG, "showController called");

		mControllerFragment.show();
		mIsControllerShowed = true;

		if (mHideControllerTimer != null) {
			mHideControllerTimer.cancel();
			mHideControllerTimer = null;
		}
	}

	public void hideController() {
		Log.d(Constant.TAG, "hideController called");

		mControllerFragment.hide();
		mIsControllerShowed = false;

		if (mHideControllerTimer != null) {
			mHideControllerTimer.cancel();
			mHideControllerTimer = null;
		}
	}

	public void setProgress(int progress) 
	{
		mControllerFragment.setProgress(progress);
		mControllerFragment.setCurrTime(mDateFormat.format(progress));
	}

	public void updateProgress()
	{
		setProgress(getCurrentPosition());
	}

	public void setDefination(String defination)
	{
		if (mDefinition == null || !mDefinition.equals(defination))
		{
			mDefinition = defination;
			
			if (isPlaying())
			{
				play(mM3u8Parser.getSecondLevelUrl(defination));
			}
		}
	}

	public void setCurrentVideoNum(int num) 
	{
		if (mCurrentVideoNum != num) 
		{
			mCurrentVideoNum = num;
			
			if (isPlaying()) 
			{
				play(null);
			}
		}
	}

	public void setTitle(String title) {
		mControllerFragment.setTitle(mActivity.getResources().getString(R.string.vodplayer_playing_now)+ title + 
		        mActivity.getResources().getString(R.string.vodplayer_playing_now_right));
	}

	public boolean getBufferStarted() {
		return mBufferStarted;
	}

	public void setBufferStarted(boolean value) {
		mBufferStarted = value;
	}

	public boolean getBufferCompleted() {
		return mBufferCompleted;
	}

	public void setBufferCompleted(boolean value) {
		mBufferCompleted = value;
	}

	public TimerTaskHandler getTimerTaskHandler() {
		return mTimerTaskHandler;
	}

	public SettingHandler getSettingHandler() {
		return mSettingHandler;
	}

	public M3u8Parser getM3u8Parser() {
		return mM3u8Parser;
	}

	public void setBreakpointPlay(boolean value) {
		mIsBreakpointPlay = value;
	}

	public void setVideoSizeKnown(boolean value) {
		mIsVideoSizeKnown = value;
	}

	public boolean getVideoSizeKnown() {
		return mIsVideoSizeKnown;
	}

	public void setVideoReadyToBePlayed(boolean value) {
		mIsVideoReadyToBePlayed = value;
	}

	public void setVideoWidth(int width) {
		mVideoWidth = width;
	}

	public void setVideoHeight(int height) {
		mVideoHeight = height;
	}

	public DialogInterface.OnClickListener getBlackScreenInterface() {
		return mBlackScreenInterface;
	}

	public void addKeyLeftCount() {
		mKeyLeftCount++;
	}

	public void addKeyRightCount() {
		mKeyRightCount++;
	}

	public void showSetting() {
		mSettingFragment.show();
	}

	public void showRelevance() {
//		mRelateFragment.show(mRelateBundle, mItemCode, 0.5);
	}

	public void showBuffer(int percent) {
		mContentFragment.showBuffer(percent);
	}

	public void hideBuffer() {
		mContentFragment.hideBuffer();
	}

	public void showToast(String text, int duration) {
		Toast.makeText(mActivity, text, duration).show();
	}

	public void showAlertDialog(int positiveTextId, int negativeTextId,
			OnClickListener positiveInterface,
			OnClickListener negativeInterface, int messageId) {

		AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mActivity);
		dialogBuilder.setMessage(messageId);

		if (positiveInterface != null)
			dialogBuilder.setPositiveButton(positiveTextId, positiveInterface);
		if (negativeInterface != null)
			dialogBuilder.setNegativeButton(negativeTextId, negativeInterface);

		mContentFragment.hideBuffer();
		dialogBuilder.show();
	}

	public void nextActivity() {
//		Intent intent = new Intent(mActivity, PlayEndActivity.class);
//		intent.putExtras(mExtras);
//
//		mActivity.startActivity(intent);
	}
}